我們昨天提到了原生的一些log機制,今天來看看.Net Core中的log 機制是如何使用及原理吧
我們昨天有提到
通常一個log事件可以拆分為
在dotnet core 中代表這三個東西的物件分別為
EventId.cs
public readonly struct EventId
{
public static implicit operator EventId(int i)
{
return new EventId(i);
}
public static bool operator ==(EventId left, EventId right)
{
return left.Equals(right);
}
public static bool operator !=(EventId left, EventId right)
{
return !left.Equals(right);
}
public EventId(int id, string? name = null)
{
Id = id;
Name = name;
}
public int Id { get; }
public string? Name { get; }
public override string ToString()
{
return Name ?? Id.ToString();
}
public bool Equals(EventId other)
{
return Id == other.Id;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is null)
{
return false;
}
return obj is EventId eventId && Equals(eventId);
}
public override int GetHashCode()
{
return Id;
}
}
可以看見EventId 本身為record struct 類型
意即本身是不可變的(immutable)
且額外做了隱含轉換,可以將事件Id轉成事件本身表示
var eventId = new EventId(1);
const int id = 1;
// True
Console.WriteLine(eventId == id);
LogLevel.cs
public enum LogLevel
{
Trace = 0,
Debug = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
None = 6,
}
log的等級大致上可以分成7種Critical
為最嚴重,Trace
為最輕微None
我還真的不知道他要幹嘛用
下面是微軟官方對各等級的介紹
LogLevel | 值 | 方法 | 描述 |
---|---|---|---|
Trace | 0 | LogTrace | 包含最詳細的訊息。 這些訊息可能包含敏感性應用程式資料。 這些訊息預設會停用,且不應在生產環境中啟用。 |
Debug | 1 | LogDebug | 用於偵錯和開發。 由於大量,因此在生產環境中請謹慎使用。 |
Information | 2 | LogInformation | 追蹤一般應用程式流程。 可能具有長期值。 |
Warning | 3 | LogWarning | 針對異常或意外事件。 通常包含不會導致應用程式失敗的錯誤或狀況。 |
Error | 4 | LogError | 發生無法處理的錯誤和例外狀況。 這些訊息指出目前作業或要求中發生失敗,而不是整個應用程式的失敗。 |
Critical | 5 | LogCritical | 發生需要立即注意的失敗。 範例:資料遺失情況、磁碟空間不足。 |
None | 6 | 指定不應該寫入任何訊息。 |
等等回頭看,我們先說說dotnet core中怎麼使用log
.Net Core 中log的核心物件有3個
在細講log的組成前,先來看看怎麼用
var logger = new ServiceCollection()
// add log and configuration console providers
.AddLogging(builder => builder.AddConsole())
.BuildServiceProvider()
.GetRequiredService<ILogger<Program>>();
var errorMessage = "This is an error message";
logger.Log(LogLevel.Information, "info");
logger.Log(LogLevel.Error, "error with compiled time constant message: {ErrorMessage}", errorMessage);
logger.Log(LogLevel.Critical, $"error with message: {errorMessage}");
logger.LogWarning("warning with message: {0}", errorMessage);
透過在 AddLogging()
做Log的初始化設定builder.AddConsole()
表示 要新增一個輸出log到 Console 的 ILoggerProvier
至於ILogger
的用法主要有兩種
logger.Log(LogLevel, msg)
logger.LogWarning(msg)
logger.Log(LogLevel.Warning, msg)
另外可以看到我在 Error, Critical, Warning 的message 中動了點手腳
Crital 的地方是透過字串插補的方式去寫入
而Error跟Wraning的地方則是比較像是string.Format
的方式
這個跟前面跳過的LoggerMessage有點關係。
LoggingServiceCollectionExtensions.cs
services.TryAdd(ServiceDescriptor.Singleton<ILoggerFactory, LoggerFactory>());
services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));
// log過濾設定
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<LoggerFilterOptions>>(
new DefaultLoggerLevelConfigureOptions(LogLevel.Information)));
}
AddLogging()
的方法中比較重要的是這三行
註冊了 ILoggerFactory
,ILogger
另外設定了Default的Filter 來過濾最低LogLevel
為LogLevel.Information
我們也可以透過SetMinimumLevel(LogLevel)
來設定最低log層級
var logger = new ServiceCollection()
.AddLogging(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Error))
我們的老朋友Provider 又來了,好像每一章都有他的存在
我們在紀錄log的時候,都是因為有必要才記,既然記了
勢必要有地方輸出log,不論是檔案,DB,MQ,或是螢幕
而實際上輸出這些log的東西就是ILoggerProvider
public interface ILoggerProvider : IDisposable
{
ILogger CreateLogger(string categoryName);
}
Category 表示事件(log)的來源來自誰,是由誰寫入的,通常是類別,或是元件 或 service
我們前面在注入 ILogger<Program>
的時候
實際上會建立一個categrayName 為 Program
的ILogger
透過強型別去避免輸入錯誤
今天身體不大舒服,把ILogger
,ILoggerFactory
,LoggerMessage
放在明天一起講